package priv.conceit.sc.hoxton.file.handle.source;

import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import priv.conceit.sc.hoxton.common.entity.file.dto.FilePathDTO;
import priv.conceit.sc.hoxton.common.entity.file.dto.FilePreviewDTO;
import priv.conceit.sc.hoxton.common.util.DateTimeUtil;
import priv.conceit.sc.hoxton.common.util.FileUtil;
import priv.conceit.sc.hoxton.common.util.IoUtil;
import priv.conceit.sc.hoxton.file.config.FileProperties;
import priv.conceit.sc.hoxton.file.handle.preview.AbsPreviewHandle;
import priv.conceit.sc.hoxton.file.handle.preview.PreviewHandleFactory;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * sc-hoxton 本地文件存储实现
 *
 * @author Conceit
 * 2020/5/12 增加方法
 * @since 1.0.0, 2020/5/12
 */

@Component
public class LocalSourceHandle extends AbsSourceHandle {

	@Autowired
	FileProperties fileProperties;

	@Autowired
	PreviewHandleFactory previewHandleFactory;

	/**
	 * 上传文件
	 *
	 * @param file
	 * @return FilePathDetail
	 * @author conceit
	 * @date 2020/5/15 21:21
	 */
	@Override
	public FilePathDTO upload(File file) {
		if (!file.exists()) {
			//todo exception
			throw new IllegalArgumentException();
		}


		return null;
	}

	/**
	 * 上传文件
	 *
	 * @param file {@link org.springframework.web.multipart}
	 * @return FilePathDTO 文件路径信息封装
	 * @author conceit
	 * @date 2020/5/15 21:21
	 */
	@Override
	public FilePathDTO upload(MultipartFile file) throws Exception{

		if (!FileUtil.hasUploadFile(file)) {
			//todo exception
			throw new IllegalArgumentException();
		}

		LocalDateTime now = LocalDateTime.now();
		//生成前半段路径
		FilePathDTO filePathDetail = buildSavedMidPathName(now);
		File praeviaAndMidPath = new File(filePathDetail.getPraeviaPath(), filePathDetail.getSavedMidPath());
		if (!praeviaAndMidPath.exists()) {
			praeviaAndMidPath.mkdirs();
		}
		//获取真实文件名
		filePathDetail = buildSavedFileName(filePathDetail, file.getOriginalFilename());
		//转存文件
		try {
			file.transferTo(new File(filePathDetail.getFullPath()));
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		return filePathDetail;
	}

	/**
	 * 删除文件
	 *
	 * @param savedFileName 文件实际保存名
	 * @return boolean
	 * @author conceit
	 * @date 2020/5/15 21:21
	 */
	@Override
	public boolean del(String savedFileName) {
		if (StrUtil.isBlank(savedFileName)) {
			throw new IllegalArgumentException();
		}
		FilePathDTO fileDetail = this.parseSavedFileName(savedFileName);
		return new File(fileDetail.getFullPath()).delete();
	}

	/**
	 * 预览文件
	 *
	 * @param savedFileName 文件实际保存名
	 * @return FilePreviewDetail 文件预览封装的信息
	 * @author conceit
	 * @date 2020/5/15 21:21
	 */
	@Override
	public FilePreviewDTO preview(String savedFileName) {
		if (StrUtil.isBlank(savedFileName)) {
			throw new IllegalArgumentException();
		}
		FilePathDTO filePathDetail=this.parseSavedFileName(savedFileName);

		//已转换的文件是否命中
		AbsPreviewHandle absPreviewHandle =previewHandleFactory.create(savedFileName);
		FilePreviewDTO convertTemp=absPreviewHandle.getConvertTemp(filePathDetail);
		if(Objects.nonNull(convertTemp)){
			return convertTemp;
		}
		//获取流
		return  absPreviewHandle.preview(filePathDetail,new File(filePathDetail.getFullPath()));
	}

	/**
	 * 下载文件
	 *
	 * @param savedFileName 文件实际保存名
	 * @return byte[]
	 * @author conceit
	 * @date 2020/5/15 21:21
	 */
	@Override
	public byte[] download(String savedFileName) {
		if (StrUtil.isBlank(savedFileName)) {
			throw new IllegalArgumentException();
		}
		FilePathDTO fileDetail = parseSavedFileName(savedFileName);
		return IoUtil.toByteArrayUseFileChannel(new File(fileDetail.getFullPath()));
	}


	/**
	 * 生成 真实保存的文件名
	 *
	 * @param filePathDTO 封装的中间路径信息
	 * @param originalName 文件提交名称
	 * @return FilePathDTO 将生成的文件路径信息 封装回去
	 * @author conceit
	 * @date 2020/5/15 21:21
	 */
	@Override
	public FilePathDTO buildSavedFileName(@NotNull FilePathDTO filePathDTO, @NotBlank String originalName) {

        /*
         * 生成最终文件名 一级目录格式化名+二级目录格式化名+文件短编码+文件原始名
         */
		String shortCode = generateShortCode();
		StringBuilder savedFileName = new StringBuilder();
		savedFileName.append(filePathDTO.getFirstName());
		savedFileName.append(fileProperties.getUpload().getSavedName().getSignSeparator());
		savedFileName.append(filePathDTO.getSecondName());
		savedFileName.append(fileProperties.getUpload().getSavedName().getSignSeparator());
		savedFileName.append(shortCode);
		savedFileName.append(fileProperties.getUpload().getSavedName().getSignSeparator());
		savedFileName.append(originalName);
		filePathDTO.setSavedFileName(savedFileName.toString());
		filePathDTO.setOriginalName(originalName);
		filePathDTO.setShortCode(shortCode);

		/*
		 * 生成全路径 前置文件夹+中间路径文件夹+最终文件生成名
		 */
		StringBuilder fileFullPath = new StringBuilder();
		fileFullPath.append(filePathDTO.getPraeviaPath());
		fileFullPath.append(File.separator);
		fileFullPath.append(filePathDTO.getSavedMidPath());
		fileFullPath.append(File.separator);
		fileFullPath.append(savedFileName);
		filePathDTO.setFullPath(fileFullPath.toString());

		return filePathDTO;
	}
	/**
	 * 生成 真实保存中间文件夹名 由一级和二级目录合并而成
	 * 或者叫卷名 组名（fastDfs）  实际上也就是文件夹名 =_=!!
	 *
	 * @param localDateTime 传入的时间
	 * @return FilePathDTO 封装的中间路径信息
	 * @author conceit
	 * @date 2020/5/15 22:05
	 */
	@Override
	public FilePathDTO buildSavedMidPathName(LocalDateTime localDateTime) {
		FilePathDTO filePathDetail = new FilePathDTO();
		StringBuilder midPath = new StringBuilder();
		//格式化一级目录
		String firstName = DateTimeUtil.format(localDateTime, fileProperties.getUpload().getSavedMidPath().getFirstFormat());
		midPath.append(firstName);
		midPath.append(File.separator);
		//格式化二级目录
		String secondName = DateTimeUtil.format(localDateTime, fileProperties.getUpload().getSavedMidPath().getSecondFormat());
		midPath.append(secondName);
		midPath.append(File.separator);
		filePathDetail.setSavedMidPath(midPath.toString());
		filePathDetail.setFirstName(firstName);
		filePathDetail.setSecondName(secondName);

		filePathDetail.setPraeviaPath(fileProperties.getSource().getLocal().getUploadDir());

		return filePathDetail;
	}

	/**
	 * 解析已保存的文件名 为相关文件路径等细节
	 *
	 * @param savedFileName 文件提交名称
	 * @return FilePathDetail
	 * @author conceit
	 * @date 2020/5/15 21:21
	 */
	@Override
	public FilePathDTO parseSavedFileName(String savedFileName) {
		if (StrUtil.isBlank(savedFileName)) {
			throw new IllegalArgumentException();
		}
		FilePathDTO filePathDetail = new FilePathDTO();

		List<String> strs =
				Stream
						.of(savedFileName.split(fileProperties.getUpload().getSavedName().getSignSeparator()))
						.collect(Collectors.toList());
		String first = strs.get(0);
		String second = strs.get(1);
		filePathDetail.setFirstName(first);
		filePathDetail.setSecondName(second);

		String afterStr = strs.stream().skip(3).collect(Collectors.joining());

		filePathDetail.setOriginalName(afterStr);
		filePathDetail.setPraeviaPath(fileProperties.getSource().getLocal().getUploadDir());

		StringBuffer midPath = new StringBuffer();
		midPath.append(File.separator);
		midPath.append(first);
		midPath.append(File.separator);
		midPath.append(second);
		midPath.append(File.separator);
		filePathDetail.setSavedMidPath(midPath.toString());

		filePathDetail.setSavedFileName(savedFileName);

		StringBuffer fullPath = new StringBuffer();
		fullPath.append(fileProperties.getSource().getLocal().getUploadDir());
		fullPath.append(File.separator);
		fullPath.append(midPath);
		fullPath.append(savedFileName);
		filePathDetail.setFullPath(fullPath.toString());

		return filePathDetail;
	}

}
